home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / tmp.c < prev    next >
C/C++ Source or Header  |  1994-01-13  |  19KB  |  850 lines

  1. /* tmp.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  *
  9.  * Modified by Tom Bodoh 02/10/93 to preserve the protection of previous
  10.  * version of the edited file instead of using the user default protection.
  11.  */
  12.  
  13.  
  14. /* This file contains functions which create & readback a TMPFILE */
  15.  
  16.  
  17. #ifdef AIX
  18. # define _XOPEN_SOURCE
  19. # include <sys/mode.h>
  20. # include <sys/stat.h>
  21. #endif
  22. #include "config.h"
  23. #include "vi.h"
  24. #if TOS
  25. # include <stat.h>
  26. #else
  27. # if OSK
  28. #  include "osk.h"
  29. # else
  30. #  if AMIGA
  31. #   include "amistat.h"
  32. #  else
  33. #   include <sys/stat.h>
  34. #  endif
  35. # endif
  36. #endif
  37. #if TURBOC
  38. # include <process.h>
  39. #endif
  40.  
  41. #ifndef NO_MODELINES
  42. static void do_modelines(l, stop)
  43.     long    l;    /* line number to start at */
  44.     long    stop;    /* line number to stop at */
  45. {
  46.     char    *str;    /* used to scan through the line */
  47.     char    *start;    /* points to the start of the line */
  48.     char    buf[80];
  49.  
  50.     /* if modelines are disabled, then do nothing */
  51.     if (!*o_modelines)
  52.     {
  53.         return;
  54.     }
  55.  
  56.     /* for each line... */
  57.     for (; l <= stop; l++)
  58.     {
  59.         /* for each position in the line.. */
  60.         for (str = fetchline(l); *str; str++)
  61.         {
  62.             /* if it is the start of a modeline command... */
  63.             if ((str[0] == 'e' && str[1] == 'x'
  64.               || str[0] == 'v' && str[1] == 'i')
  65.               && str[2] == ':')
  66.             {
  67.                 start = str += 3;
  68.  
  69.                 /* find the end */
  70.                 for (str = start + strlen(start); *--str != ':'; )
  71.                 {
  72.                 }
  73.  
  74.                 /* if it is a well-formed modeline, execute it */
  75.                 if (str > start && str - start < sizeof buf)
  76.                 {
  77.                     strncpy(buf, start, (int)(str - start));
  78.                     buf[(int)(str - start)] = '\0';
  79.                     doexcmd(buf, '\\');
  80.                     break;
  81.                 }
  82.             }
  83.         }
  84.     }
  85. }
  86. #endif
  87.  
  88.  
  89. /* The FAIL() macro prints an error message and then exits. */
  90. #define FAIL(why,arg)    mode = MODE_EX; msg(why, arg); endwin(); exit(9)
  91.  
  92. /* This is the name of the temp file */
  93. static char    tmpname[80];
  94.  
  95. /* This function creates the temp file and copies the original file into it.
  96.  * Returns if successful, or stops execution if it fails.
  97.  */
  98. int tmpstart(filename)
  99.     char        *filename; /* name of the original file */
  100. {
  101.     int        origfd;    /* fd used for reading the original file */
  102.     struct stat    statb;    /* stat buffer, used to examine inode */
  103.     REG BLK        *this;    /* pointer to the current block buffer */
  104.     REG BLK        *next;    /* pointer to the next block buffer */
  105.     int        inbuf;    /* number of characters in a buffer */
  106.     int        nread;    /* number of bytes read */
  107.     REG int        j, k;
  108.     int        i;
  109.     long        nbytes;
  110.  
  111.     /* switching to a different file certainly counts as a change */
  112.     changes++;
  113.     redraw(MARK_UNSET, FALSE);
  114.  
  115.     /* open the original file for reading */
  116.     *origname = '\0';
  117.     if (filename && *filename)
  118.     {
  119.         strcpy(origname, filename);
  120.         origfd = open(origname, O_RDONLY);
  121.         if (origfd < 0 && errno != ENOENT)
  122.         {
  123.             msg("Can't open \"%s\"", origname);
  124.             return tmpstart("");
  125.         }
  126.         if (origfd >= 0)
  127.         {
  128.             if (stat(origname, &statb) < 0)
  129.             {
  130.                 FAIL("Can't stat \"%s\"", origname);
  131.             }
  132. #if TOS
  133.             if (origfd >= 0 && (statb.st_mode & S_IJDIR))
  134. #else
  135. # if OSK
  136.             if (origfd >= 0 && (statb.st_mode & S_IFDIR))
  137. # else
  138.             if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG)
  139. # endif
  140. #endif
  141.             {
  142.                 msg("\"%s\" is not a regular file", origname);
  143.                 return tmpstart("");
  144.             }
  145.         }
  146.         else
  147.         {
  148.             stat(".", &statb);
  149.         }
  150.         if (origfd >= 0)
  151.         {
  152.             origtime = statb.st_mtime;
  153. #if OSK
  154.             if (*o_readonly || !(statb.st_mode &
  155.                   ((getuid() >> 16) == 0 ? S_IOWRITE | S_IWRITE :
  156.                   ((statb.st_gid != (getuid() >> 16) ? S_IOWRITE : S_IWRITE)))))
  157. #endif
  158. #if AMIGA || MSDOS || OS2
  159.             if (*o_readonly || !(statb.st_mode & S_IWRITE))
  160. #endif
  161. #if TOS
  162. # ifdef __GNUC__ 
  163.             if (*o_readonly || !(statb.st_mode & S_IWRITE))
  164. # else
  165.             if (*o_readonly || (statb.st_mode & S_IJRON))
  166. # endif
  167. #endif
  168. #if ANY_UNIX
  169.             if (*o_readonly || !(statb.st_mode &
  170.                   ((geteuid() == 0) ? 0222 :
  171.                   ((statb.st_uid != geteuid() ? 0022 : 0200)))))
  172. #endif
  173. #if VMS
  174.             if (*o_readonly)
  175. #endif
  176.             {
  177.                 setflag(file, READONLY);
  178.             }
  179.         }
  180.         else
  181.         {
  182.             origtime = 0L;
  183.         }
  184.     }
  185.     else
  186.     {
  187.         origfd = -1;
  188.         origtime = 0L;
  189.         stat(".", &statb);
  190.     }
  191.  
  192.     /* make a name for the tmp file */
  193.     do
  194.     {
  195.         tmpnum++;
  196. #if MSDOS || TOS || OS2
  197.         /* MS-Dos doesn't allow multiple slashes, but supports drives
  198.          * with current directories.
  199.          * This relies on TMPNAME beginning with "%s\\"!!!!
  200.          */
  201.         strcpy(tmpname, o_directory);
  202.         if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1]))
  203.             tmpname[i++]=SLASH;
  204.         sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum);
  205. #else
  206.         sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum);
  207. #endif
  208.     } while (access(tmpname, 0) == 0);
  209.  
  210.     /* !!! RACE CONDITION HERE - some other process with the same PID could
  211.      * create the temp file between the access() call and the creat() call.
  212.      * This could happen in a couple of ways:
  213.      * - different workstation may share the same temp dir via NFS.  Each
  214.      *   workstation could have a process with the same number.
  215.      * - The DOS version may be running multiple times on the same physical
  216.      *   machine in different virtual machines.  The DOS pid number will
  217.      *   be the same on all virtual machines.
  218.      *
  219.      * This race condition could be fixed by replacing access(tmpname, 0)
  220.      * with open(tmpname, O_CREAT|O_EXCL, 0600), if we could only be sure
  221.      * that open() *always* used modern UNIX semantics.
  222.      */
  223.  
  224.     /* create the temp file */
  225. #if ANY_UNIX
  226.     close(creat(tmpname, 0600));        /* only we can read it */
  227. #else
  228.     close(creat(tmpname, FILEPERMS));    /* anybody body can read it, alas */
  229. #endif
  230.     tmpfd = open(tmpname, O_RDWR | O_BINARY);
  231.     if (tmpfd < 0)
  232.     {
  233.         FAIL("Can't create temp file... Does directory \"%s\" exist?", o_directory);
  234.         return 1;
  235.     }
  236.  
  237.     /* allocate space for the header in the file */
  238.     if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) < BLKSIZE
  239.      || write(tmpfd, tmpblk.c, (unsigned)BLKSIZE) < BLKSIZE)
  240.     {
  241.         FAIL("Error writing headers to \"%s\"", tmpname);
  242.     }
  243.  
  244. #ifndef NO_RECYCLE
  245.     /* initialize the block allocator */
  246.     /* This must already be done here, before the first attempt
  247.      * to write to the new file! GB */
  248.     garbage();
  249. #endif
  250.  
  251.     /* initialize lnum[] */
  252.     for (i = 1; i < MAXBLKS; i++)
  253.     {
  254.         lnum[i] = INFINITY;
  255.     }
  256.     lnum[0] = 0;
  257.  
  258.     /* if there is no original file, then create a 1-line file */
  259.     if (origfd < 0)
  260.     {
  261.         *o_newfile = TRUE;
  262.  
  263.         hdr.n[0] = 0;    /* invalid inode# denotes new file */
  264.  
  265.         this = blkget(1);     /* get the new text block */
  266.         strcpy(this->c, "\n");    /* put a line in it */
  267.  
  268.         lnum[1] = 1L;    /* block 1 ends with line 1 */
  269.         nlines = 1L;    /* there is 1 line in the file */
  270.         nbytes = 1L;
  271.  
  272.         if (*origname)
  273.         {
  274.             msg("\"%s\" [NEW FILE]  1 line, 1 char", origname);
  275.         }
  276.         else
  277.         {
  278.             msg("\"[NO FILE]\"  1 line, 1 char");
  279.         }
  280.     }
  281.     else /* there is an original file -- read it in */
  282.     {
  283.         nbytes = nlines = 0;
  284.         *o_newfile = FALSE;
  285.  
  286.         /* preallocate 1 "next" buffer */
  287.         i = 1;
  288.         next = blkget(i);
  289.         inbuf = 0;
  290.  
  291.         /* loop, moving blocks from orig to tmp */
  292.         for (;;)
  293.         {
  294.             /* "next" buffer becomes "this" buffer */
  295.             this = next;
  296.  
  297.             /* read [more] text into this block */
  298.             nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf);
  299.             if (nread < 0)
  300.             {
  301.                 close(origfd);
  302.                 close(tmpfd);
  303.                 tmpfd = -1;
  304.                 unlink(tmpname);
  305.                 FAIL("Error reading \"%s\"", origname);
  306.             }
  307.  
  308.             /* convert NUL characters to something else */
  309.             for (j = k = inbuf; k < inbuf + nread; k++)
  310.             {
  311.                 if (!this->c[k])
  312.                 {
  313.                     setflag(file, HADNUL);
  314.                     this->c[j++] = 0x80;
  315.                 }
  316. #ifndef CRUNCH
  317.                 else if (*o_beautify && this->c[k] < ' ' && this->c[k] >= 1)
  318.                 {
  319.                     if (this->c[k] == '\t'
  320.                      || this->c[k] == '\n'
  321.                      || this->c[k] == '\f')
  322.                     {
  323.                         this->c[j++] = this->c[k];
  324.                     }
  325.                     else if (this->c[k] == '\b')
  326.                     {
  327.                         /* delete '\b', but complain */
  328.                         setflag(file, HADBS);
  329.                     }
  330.                     /* else silently delete control char */
  331.                 }
  332. #endif
  333.                 else
  334.                 {
  335.                     this->c[j++] = this->c[k];
  336.                 }
  337.             }
  338.             inbuf = j;
  339.  
  340.             /* if the buffer is empty, quit */
  341.             if (inbuf == 0)
  342.             {
  343.                 goto FoundEOF;
  344.             }
  345.  
  346. #if MSDOS || TOS || OS2
  347. /* BAH! MS text mode read fills inbuf, then compresses eliminating \r
  348.    but leaving garbage at end of buf. The same is true for TURBOC. GB. */
  349.  
  350.             memset(this->c + inbuf, '\0', BLKSIZE - inbuf);
  351. #endif
  352.  
  353.             /* search backward for last newline */
  354.